package com.yfp.operation.service.impl;

import com.yfp.common.core.enums.PayStatusEnum;
import com.yfp.common.security.utils.SecurityUtils;
import com.yfp.operation.domain.*;
import com.yfp.operation.domain.dto.SubAccountDTO;
import com.yfp.operation.domain.dto.UserWithdrawCheckDTO;
import com.yfp.operation.domain.vo.SharingVO;
import com.yfp.operation.domain.vo.SubAccountVO;
import com.yfp.operation.enums.UserBillStatusEnums;
import com.yfp.operation.enums.UserWithdrawDetailStatusEnums;
import com.yfp.operation.enums.UserWithdrawStatusEnums;
import com.yfp.operation.mapper.UserAccountMapper;
import com.yfp.operation.mapper.UserBillMapper;
import com.yfp.operation.service.*;
import com.yfp.operation.domain.*;
import com.yfp.operation.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 用户分成账单
 * 
 * @CreateDate: 2024/5/28 14:21
 * @UpdateUser: 
 * @UpdateDate: 2024/5/28 14:21
 * @UpdateRemark: 暂无修改
 * @Version: 1.0
 */
@Service
@Slf4j
public class UserBillServiceImpl implements UserBillService {
    @Autowired
    private UserBillMapper userBillMapper;
    @Autowired
    private MachineService machineService;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderComboService orderComboService;
    @Autowired
    private OrderListService orderListService;
    @Autowired
    private PositionService positionService;
    @Autowired
    private UserAccountService userAccountService;
    @Autowired
    private PositionSharingService positionSharingService;
    @Autowired
    private UserWithdrawService userWithdrawService;
    @Autowired
    private UserWithdrawDetailService userWithdrawDetailService;
    @Autowired
    private UserAccountMapper userAccountMapper;
    @Autowired
    private BillProfitSharingService billProfitSharingService;
    private final SqlSessionFactory sqlSessionFactory;

    public UserBillServiceImpl(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    @Override
    public UserBill findById(Long id) {
        return userBillMapper.findById(id);
    }

    /**
     * 订单分成
     *
     * @param orderSn 订单编号
     */

    @Override
    @Transactional
    public void orderRouting(String orderSn, Integer payType) {
        OrderComboDO orderComboDO = orderComboService.getOrderComboByOrderId(orderSn);
        MachineDO machineDO = machineService.getMachine(orderComboDO.getMachineId());
        log.info("订单分成-订单编号: {}， payType:{}，positionId:{}", orderSn, payType == 1 ? "支付宝" : "微信", machineDO.getPositionId());
        // 点位分成信息
        List<PositionSharing> positionSharings = positionSharingService.getByPositionId(machineDO.getPositionId());
        log.info("点位分成信息: {}", positionSharings);
        if (positionSharings.isEmpty()) {
            // 没有分账接收方则不需要分成
            return;
        }
        PositionDO positionDO = positionService.getById(machineDO.getPositionId());
        // 设备手续费用(百分比)
        BigDecimal feeRate = positionDO.getFeeRate();
        for (PositionSharing positionSharing : positionSharings) {
            List<OrderListDO> orderListDOS = orderListService.getByOrderSn(orderSn);
            log.info("orderListDOS:{}", orderListDOS);
            // 设备分成比率(百分比)
            BigDecimal proportion = positionSharing.getProportion();
            if (feeRate == null || feeRate.doubleValue()== 0 || proportion == null || proportion.doubleValue() == 0) {
                continue;
            }

            // 订单总额
            BigDecimal orderMoney = BigDecimal.valueOf(0);
            // 赠送金总额
            BigDecimal giftGold = BigDecimal.valueOf(0);
            for (OrderListDO orderListDO : orderListDOS) {
                BigDecimal amt = new BigDecimal(orderListDO.getAmt());
                orderMoney = orderMoney.add(amt.multiply(new BigDecimal(orderListDO.getCount())));
                giftGold = giftGold.add(null == orderListDO.getGiftGold()?BigDecimal.valueOf(0):orderListDO.getGiftGold());
                log.info("giftGold:{}", giftGold);
            }
            BigDecimal feeRateD = feeRate.divide(BigDecimal.valueOf(100));
            BigDecimal proportionD = proportion.divide(BigDecimal.valueOf(100));

            // 订单手续费， 向上取整
            BigDecimal fee = orderMoney.multiply(feeRateD).setScale(2, BigDecimal.ROUND_UP);
            // 订单分成,向下取整
            BigDecimal money = orderMoney.subtract(giftGold).subtract(fee).multiply(proportionD).setScale(2, BigDecimal.ROUND_DOWN);

            UserBill userBill = new UserBill();
            userBill.setFee(fee);
            userBill.setFeeRate(feeRate);
            userBill.setMoney(money);
            userBill.setPayMoney(orderMoney.subtract(giftGold));
            userBill.setProportion(proportion);
            userBill.setOrderSn(orderSn);
            userBill.setRefundMoney(BigDecimal.valueOf(0));
            userBill.setUserId(positionSharing.getUserId());
            userBill.setStatus(UserBillStatusEnums.FREEZE.getStatus());
            userBill.setPayType(payType);
            userBill.setMachineId(machineDO.getMachineId());
            userBill.setMachineName(machineDO.getMachineName());
            userBill.setFreezeDay(positionSharing.getFreezeDay());
            userBill.setPositionId(positionDO.getPositionId());
            userBill.setIndependentUserId(positionDO.getInvestorUserId());
            userBill.setIndependentAccount(positionDO.getProceedsAccount());
            userBill.setUserType(positionSharing.getType());
            userBill.setReceiveAccount(positionSharing.getAccountNumber());
            userBill.setGiftGold(giftGold);
            userBillMapper.add(userBill);

            UserAccount userAccount = userAccountService.findByUserId(userBill.getUserId());
            // 添加冻结额度
            if (null == userAccount) {
                userAccount = new UserAccount();
                userAccount.setUserId(userBill.getUserId());
                userAccount.setBalance(BigDecimal.valueOf(0));
                userAccount.setWithdrawnMoney(BigDecimal.valueOf(0));
                userAccount.setAuditWithdrawnMoney(BigDecimal.valueOf(0));
                userAccount.setFrozenMoney(userBill.getMoney());
                userAccountService.add(userAccount);
            } else {
                userAccount.setFrozenMoney(userAccount.getFrozenMoney().add(userBill.getMoney()));
                userAccountService.edit(userAccount);
            }
        }
    }


    /**
     * 订单退款扣除之前的分成
     * @param orderSn
     * @param refundMoney
     */
    @Override
    @Transactional
    public void orderReimburse(String orderSn, BigDecimal refundMoney) {
        log.info("订单退款扣除之前的分成");
        List<UserBill> userBills = userBillMapper.findByOrderSn(orderSn);
        if (userBills.isEmpty()) {
            return;
        }
        for (UserBill userBill : userBills) {
            log.info("历史分账人退款单号：{}", userBill.getOrderSn());
            UserAccount userAccount = userAccountService.findByUserId(userBill.getUserId());
            if (userBill.getStatus() == UserBillStatusEnums.FREEZE.getStatus()) {
                // 减除上次订单分成 再加退款后的分成
                userAccount.setFrozenMoney(userAccount.getFrozenMoney().subtract(userBill.getMoney()));
            } else {
                // 减除上次订单分成 再加退款后的分成
                userAccount.setBalance(userAccount.getBalance().subtract(userBill.getMoney()));
            }
            userAccountService.edit(userAccount);
//            userBill.setRefundMoney(BigDecimal.valueOf(0));
            userBill.setMoney(BigDecimal.valueOf(0));
            userBill.setFee(BigDecimal.valueOf(0));
            userBill.setGiftGold(BigDecimal.valueOf(0));
            userBillMapper.edit(userBill);
        }
//        OrderComboDO orderComboDO = orderComboService.getOrderComboByOrderId(orderSn);
        List<OrderListDO> orderListDOS = orderListService.getByOrderSn(orderSn);
        MachineDO machineDO = machineService.getMachine(orderListDOS.get(0).getMachineId());
        // 点位分成信息
        List<PositionSharing> positionSharings = positionSharingService.getByPositionId(machineDO.getPositionId());
        if (positionSharings.isEmpty()) {
            // 没有分账接收方则不需要分成
            return;
        }
        Map<Long, PositionSharing> positionSharingMap = positionSharings.stream().collect(Collectors.toMap(PositionSharing::getUserId, positionSharing -> positionSharing));
        // 点位信息
        PositionDO positionDO = positionService.getById(machineDO.getPositionId());
        // 设备手续费用(百分比)
        BigDecimal feeRate = positionDO.getFeeRate();

        for (UserBill userBill : userBills) {
            // 设备分成比率(百分比)
            PositionSharing positionSharing = positionSharingMap.get(userBill.getUserId());
            BigDecimal proportion = null != positionSharing ?positionSharing.getProportion() : BigDecimal.valueOf(0);
            if (feeRate == null ) {
                feeRate = BigDecimal.valueOf(0);
            }
            // 订单总额
            BigDecimal orderMoney = BigDecimal.valueOf(0);
            // 赠送金总额
            BigDecimal giftGold = BigDecimal.valueOf(0);

            // 订单退款总额
//            BigDecimal orderRefundMoney = BigDecimal.valueOf(0);
            for (OrderListDO orderListDO : orderListDOS) {
                BigDecimal amt = new BigDecimal(orderListDO.getAmt());
                orderMoney = orderMoney.add(amt.multiply(new BigDecimal(orderListDO.getCount())));
                if (orderListDO.getPayType().equals("3")){
                    giftGold = giftGold.add(null == orderListDO.getGiftGold() ? giftGold:orderListDO.getGiftGold());
                }
//                orderRefundMoney = orderRefundMoney.add(new BigDecimal(orderListDO.getRefundSn()));
            }

            // 订单退款总额
            BigDecimal orderRefundMoney = userBill.getRefundMoney() == null ? refundMoney : userBill.getRefundMoney().add(refundMoney);
            // 部分退款
            if (orderMoney.compareTo(orderRefundMoney) == 1) {
                log.info("部分退款：orderMoney：{} ，orderRefundMoney：{} ", orderMoney , orderRefundMoney);
                // 支付费率
                BigDecimal feeRateD = feeRate.divide(BigDecimal.valueOf(100));
                // 分成比例
                BigDecimal proportionD = proportion.divide(BigDecimal.valueOf(100));
                // 订单金额减给退款 总分成金额
                BigDecimal sharing = orderMoney.subtract(orderRefundMoney).subtract(giftGold).setScale(2);
                // 订单手续费， 向上取整
                BigDecimal fee = sharing.multiply(feeRateD).setScale(2, BigDecimal.ROUND_UP);

                // 订单分成,向下取整 -手续费再分成
//                sharing = sharing.subtract(fee);
                BigDecimal money = sharing.subtract(fee).multiply(proportionD).setScale(2, BigDecimal.ROUND_DOWN);
                userBill.setFee(fee);
                userBill.setMoney(money);
                userBill.setPayMoney(sharing);
                userBill.setGiftGold(giftGold);
                userBill.setRefundMoney(orderRefundMoney);
            } else {
                log.info("全部退款：orderMoney：{} ，orderRefundMoney：{} ", orderMoney , orderRefundMoney);
                userBill.setRefundMoney(orderRefundMoney);
                userBill.setMoney(BigDecimal.valueOf(0));
                userBill.setPayMoney(BigDecimal.valueOf(0));
                userBill.setGiftGold(BigDecimal.valueOf(0));
                userBill.setFee(BigDecimal.valueOf(0));
            }
            userBillMapper.edit(userBill);

            // 用户账户
            UserAccount userAccount = userAccountService.findByUserId(userBill.getUserId());
            if (userBill.getStatus() == UserBillStatusEnums.FREEZE.getStatus()){
                // 减除上次订单分成 再加退款后的分成
                userAccount.setFrozenMoney(userAccount.getFrozenMoney().add(userBill.getMoney()));
            }else  {
                // 减除上次订单分成 再加退款后的分成
                userAccount.setBalance(userAccount.getBalance().add(userBill.getMoney()));
            }
            userAccountService.edit(userAccount);
        }
    }

    /**
     * 定时任务每天凌晨2点执行
     * 订单入账
     */
    @Override
    @Transactional
    public void orderBillCarryto() {
        List<UserBill> userBills = userBillMapper.findUnfreeze();
        if (userBills.isEmpty()) {
            return;
        }
        List<Long> userBillIds = userBills.stream().map(UserBill::getId).collect(Collectors.toList());
        List<Long> userIds = userBills.stream().map(UserBill::getUserId).collect(Collectors.toList());
        List<UserAccount> userAccounts = userAccountService.findByUserIdIn(userIds);

        Map<Long, UserAccount> userAccountMap = userAccounts.stream().collect(Collectors.toMap(UserAccount::getUserId, s -> s));
        Map<Long, List<UserBill>> userBillMap = userBills.stream().collect(Collectors.groupingBy(UserBill::getUserId));

        List<UserAccount> editUserAccounts = new ArrayList<>();
        for (Long userId : userBillMap.keySet()) {
            List<UserBill> userBills1 = userBillMap.get(userId);
            // 求和本次分成总额
            BigDecimal userTotalMoney = userBills1.stream().map(UserBill::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
            UserAccount editUserAccount = userAccountMap.get(userId);
            editUserAccount.setBalance(editUserAccount.getBalance().add(userTotalMoney));
            editUserAccount.setFrozenMoney(editUserAccount.getFrozenMoney().subtract(userTotalMoney));
            editUserAccounts.add(editUserAccount);
        }
        // 更新已入账状态
        userBillMapper.editStatusInIds(userBillIds, UserBillStatusEnums.CARRYTO.getStatus());
        // 更新余额
        userAccountService.edits(editUserAccounts);
    }

    /**
     * 获取当前登录用户的分成账单
     *
     * @return
     */
    @Override
    public List<UserBill> getAccountBill() {
        Long userId = SecurityUtils.getUserId();
        return userBillMapper.getByUserId(userId);
    }

    /**
     * 获取设备分账详情列表
     * @param subAccountDTO
     * @return
     */
    @Override
    public List<SubAccountVO> subAccount(SubAccountDTO subAccountDTO) {
        return userBillMapper.subAccount(subAccountDTO);
    }

    /**
     * 获取订单分账详情列表
     * @param subAccountDTO
     * @return
     */
    @Override
    public List<UserBill> selectAllUserBill(SubAccountDTO subAccountDTO) {
        return userBillMapper.selectAllUserBill(subAccountDTO);
    }

    @Override
    public List<SharingVO> selectSharing(List<Integer> userIds) {
        return userBillMapper.selectSharing(userIds);
    }

    @Override
    public List<UserBill> getByOrderSnAndStatusNot(String orderSn, Integer status) {
        return userBillMapper.getByOrderSnAndStatusNot(orderSn, status);
    }

    @Override
    public List<UserBill> getByOrderSnAndStatus(String orderSn, Integer status) {
        return userBillMapper.getByOrderSnAndStatus(orderSn, status);
    }

    @Override
    public List<UserBill> getByIdsIn(List<Long> ids) {
        return userBillMapper.getByIdsIn(ids);
    }

    @Override
    public List<SubAccountVO> getByMachineIdAccount(SubAccountDTO subAccountDTO) {
        return userBillMapper.getByMachineIdAccount(subAccountDTO);
    }

    @Override
    public List<UserBill> selectByMachineIdUserBill(SubAccountDTO subAccountDTO) {
        return userBillMapper.selectByMachineIdUserBill(subAccountDTO);
    }

    @Override
    public List<String> getMachineId(SubAccountDTO subAccountDTO) {
        return userBillMapper.getMachineId(subAccountDTO);
    }

    @Override
    public List<UserBill> selectMachineSharing(SubAccountDTO subAccountDTO) {
        return userBillMapper.selectMachineSharing(subAccountDTO);
    }

    @Override
    public List<PositionSharing> getSharing(Set<String> orderIds) {
        return userBillMapper.getSharing(orderIds);
    }

    @Override
    public List<Integer> getUserId(String accountNumber) {
        return userBillMapper.getUserId(accountNumber);
    }

    @Override
    public void autoMakePayment() {
        log.info("=============自动申请/审核/打款===============");
        String timedTaskUser = userBillMapper.findSysDictDate("timed_task_user");
        Long auditUserId = Long.parseLong(timedTaskUser);
        // 根据用户ID 分组
        List<UserBill> userBills = userBillMapper.findOutTimeNotMakePayment();
        Map<Long, List<UserBill>> userBillMap = userBills.stream().collect(Collectors.groupingBy(s -> s.getUserId()));
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
        for (Long userId : userBillMap.keySet()) {
            try {
                List<UserBill> userBillList = userBillMap.get(userId);
                double billMoney = userBillList.stream().mapToDouble(s -> s.getMoney().doubleValue()).sum();
                log.info("userId:{}，billMoney：{}" , userId, billMoney);
                if (billMoney <= 0){
                    for (UserBill userBill : userBillList) {
                        Thread.sleep(1100);
                        List<UserBill> userBills1 = userBillMapper.findByOrderSn(userBill.getOrderSn());
                        boolean unf = true;
                        for (UserBill bill : userBills1) {
                            if (bill.getId() != userBill.getId() && bill.getStatus() !=3 ){
                                unf  = false;
                                break;
                            }
                        }
                        if (unf){
                            billProfitSharingService.unfreeze(userBill.getId());
                        }
                    }
                    continue;
                }
                Thread.sleep(5000);
                UserWithdraw userWithdraw = new UserWithdraw();
                userWithdraw.setUserId(userId);
                userWithdraw.setMoney(new BigDecimal(billMoney));
                userWithdraw.setStatus(UserWithdrawStatusEnums.PENDING_REVIEW.getStatus());
                userWithdraw.setApplyTime(new Date());
                userWithdraw.setAuditTime(new Date());
                userWithdraw.setAuditUserId(auditUserId);
                userWithdraw.setWithdrawSn(userWithdrawService.getWithdrawSn(userId));
                userWithdraw.setCurrentBalance(new BigDecimal(0));
                userWithdrawService.add(userWithdraw);
                List<UserWithdrawDetail> userWithdrawDetails = new ArrayList<>();
                UserWithdrawDetail userWithdrawDetail = null;
                for (UserBill userBill : userBillList) {
                    userWithdrawDetail = new UserWithdrawDetail();
                    userWithdrawDetail.setUserWithdrawId(userWithdraw.getId());
                    userWithdrawDetail.setUserBillId(userBill.getId());
                    userWithdrawDetail.setAccountNumber(userBill.getReceiveAccount());
                    userWithdrawDetail.setStatus(UserWithdrawDetailStatusEnums.NO.getStatus());
                    userWithdrawDetails.add(userWithdrawDetail);
                }
                userWithdrawDetailService.adds(userWithdrawDetails);
                UserAccount userAccount = userAccountMapper.getByUserId(userId);
                userAccount.setAuditWithdrawnMoney(userAccount.getAuditWithdrawnMoney().add(new BigDecimal(billMoney)));
                userAccount.setBalance(userAccount.getBalance().subtract(new BigDecimal(billMoney)));
                userAccountMapper.edit(userAccount);

                // 提交事务
                sqlSession.commit();
                sqlSession.clearCache();
                UserWithdrawCheckDTO userWithdrawCheckDTO = new UserWithdrawCheckDTO();
                userWithdrawCheckDTO.setAuditUserId(auditUserId);
                userWithdrawCheckDTO.setId(userWithdraw.getId());
                userWithdrawCheckDTO.setStatus(UserWithdrawStatusEnums.AWAITING_PAYMENT.getStatus());
                log.info("开始打款，userWithdrawId：{}" , userWithdraw.getId());
                userWithdrawService.managementWithdrawCheck(userWithdrawCheckDTO);
            }catch (Exception e){
                log.info("自动打款失败， 失败原因：{}",e.getMessage());
                e.printStackTrace();
            }
        }
        sqlSession.rollback();
        sqlSession.close();
    }

    @Override
    public void edit(UserBill userBill) {
        userBillMapper.edit(userBill);
    }
}